package com.api.utils;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.generator.MathGenerator;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.math.Calculator;
import cn.hutool.core.util.IdUtil;
import com.api.dispose.enums.CaptchaTypeEnums;
import com.api.dispose.exception.AppException;
import com.api.dispose.vo.CaptchaImageVo;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author 李大牛家的牛 (scafel@163.com)
 * @createDate 2025/5/20-14:53
 * @description TODO...
 **/
@Slf4j
@Setter
public class CaptchaUtils {

    /**
     * 验证码图片宽度
     */
    private int captcha_width = 300;
    /**
     * 验证码图片高度
     */
    private int captcha_height = 100;
    /**
     * 验证码字符个数
     */
    private int captcha_code_length = 4;
    /**
     * 验证码图片缓存超时时间 只提供参考不具备真实实现
     */
    private long captcha_code_timeout = 5 * 60;
    /**
     * 数字字符串
     */
    private static final String NUMBER_STRING = "0123456789";
    /**
     * 字母字符串
     */
    private static final String LETTER_STRING = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
    /**
     * 字母+数字字符串
     */
    private static final String LETTER_NUMBER_STRING = NUMBER_STRING + LETTER_STRING;


    /**
     * 获取GIF类型验证码图片
     *
     * @see CaptchaUtils#getCaptchaImage(CaptchaTypeEnums)
     * @author 李大牛家的牛 (scafel@163.com)
     * @return {@link CaptchaImageVo } 验证码图片对象
     */
    public static CaptchaImageVo getCaptchaGifImage() {
        CaptchaUtils captchaUtils = new CaptchaUtils();
        return captchaUtils.getCaptchaImage(CaptchaTypeEnums.GIF);
    }

    /**
     * 获取数学计算类型验证码图片
     *
     * @see CaptchaUtils#getCaptchaImage(CaptchaTypeEnums)
     * @author 李大牛家的牛 (scafel@163.com)
     * @return {@link CaptchaImageVo } 验证码图片对象
     */
    public static CaptchaImageVo getCaptchaMathImage() {
        CaptchaUtils captchaUtils = new CaptchaUtils();
        return captchaUtils.getCaptchaImage(CaptchaTypeEnums.MATH);
    }

    /**
     * 获取数字类型非GIF验证码图片
     *
     * @see CaptchaUtils#getCaptchaImage(CaptchaTypeEnums)
     * @author 李大牛家的牛 (scafel@163.com)
     * @return {@link CaptchaImageVo } 验证码图片对象
     */
    public static CaptchaImageVo getCaptchaNumberImage() {
        CaptchaUtils captchaUtils = new CaptchaUtils();
        return captchaUtils.getCaptchaImage(CaptchaTypeEnums.NUMBER);
    }

    /**
     * 获取数字+字母类型非GIF验证码图片
     *
     * @see CaptchaUtils#getCaptchaImage(CaptchaTypeEnums)
     * @author 李大牛家的牛 (scafel@163.com)
     * @return {@link CaptchaImageVo } 验证码图片对象
     */
    public static CaptchaImageVo getCaptchaNumberLetterImage() {
        CaptchaUtils captchaUtils = new CaptchaUtils();
        return captchaUtils.getCaptchaImage(CaptchaTypeEnums.NUMBER_LETTER);
    }

    /**
     * 获取字母类型非GIF验证码图片
     *
     * @see CaptchaUtils#getCaptchaImage(CaptchaTypeEnums)
     * @author 李大牛家的牛 (scafel@163.com)
     * @return {@link CaptchaImageVo } 验证码图片对象
     */
    public static CaptchaImageVo getCaptchaLetterImage() {
        CaptchaUtils captchaUtils = new CaptchaUtils();
        return captchaUtils.getCaptchaImage(CaptchaTypeEnums.LETTER);
    }


    /**
     * 获取验证码图片
     *
     * @author 李大牛家的牛 (scafel@163.com)
     * @param type {@link CaptchaTypeEnums} 验证码类型
     * @return {@link CaptchaImageVo } 验证码图片对象
     */
    public CaptchaImageVo getCaptchaImage(CaptchaTypeEnums type) {
        CaptchaImageVo dto = new CaptchaImageVo();
        AbstractCaptcha captcha = null;
        // 使用工厂模式创建验证码对象
        captcha = createCaptcha(type);
        if (captcha != null) {
            // 获取图片验证码Base64编码
            String image = captcha.getImageBase64Data();
            // 验证码唯一标识符
            String code = IdUtil.simpleUUID();
            if (type == CaptchaTypeEnums.MATH){
                final int calculateResult = (int) Calculator.conversion(captcha.getCode());
                dto.setCaptcha(String.valueOf(calculateResult));
            }else {
                dto.setCaptcha(captcha.getCode());
            }
            dto.setImg(image);
            dto.setImgCode(code);
            dto.setImgTimeout(captcha_code_timeout);
        } else {
            throw new AppException("验证码类型错误");
        }
        return dto;
    }


    /**
     * 创建验证码对象
     *
     * @author 李大牛家的牛 (scafel@163.com)
     * @param type {@link CaptchaTypeEnums} 验证码类型
     * @return {@link AbstractCaptcha } 验证码抽象类
     */
    private AbstractCaptcha createCaptcha(CaptchaTypeEnums type) {
        AbstractCaptcha captcha = null;
        try {
            switch (type) {
                case MATH:
                    captcha = CaptchaUtil.createShearCaptcha(captcha_width, captcha_height, captcha_code_length, 4);
                    captcha.setGenerator(new MathGenerator());
                    break;
                case NUMBER:
                    RandomGenerator randomGenerator = new RandomGenerator(NUMBER_STRING, captcha_code_length);
                    captcha = CaptchaUtil.createLineCaptcha(captcha_width, captcha_height);
                    captcha.setGenerator(randomGenerator);
                case LETTER:
                    captcha = CaptchaUtil.createLineCaptcha(captcha_width, captcha_height);
                    captcha.setGenerator(new RandomGenerator(LETTER_STRING, captcha_code_length));
                    break;
                case NUMBER_LETTER:
                    captcha = CaptchaUtil.createLineCaptcha(captcha_width, captcha_height);
                    captcha.setGenerator(new RandomGenerator(LETTER_NUMBER_STRING, captcha_code_length));
                    break;
                case GIF:
                default:
                    captcha = CaptchaUtil.createGifCaptcha(captcha_width, captcha_height, captcha_code_length);
                    captcha.setGenerator(new RandomGenerator(LETTER_NUMBER_STRING, captcha_code_length));
                    break;
            }
        } catch (RuntimeException e) {
            log.error("create captcha error: { }", e);
        }
        return captcha;
    }

}
